//xlang Source, Name:Client.xcsm
//Date: Sat Oct 23:18:16 2018

class Client : IClient {
    BusinessClt client;

    public Client (BusinessClt _clt) {
        client = _clt;
    }

    long alivetime = _system_.currentTimeMillis();
    RCPClient rcp = new RCPClient();

    Map<int, int> c2s_map = new Map<int, int>();//本地ID, 服务器ID
    Map<int, int> s2c_map = new Map<int, int>();// 服务器ID, 本地ID
    Map<int, ByteArrayOutputStream> id_buffer = new Map<int, ByteArrayOutputStream>();// 缓存器

    public void resetAlive() {
        alivetime = _system_.currentTimeMillis();
    }

    public bool isAlive() {
        return (_system_.currentTimeMillis() - alivetime) < RCPClient.TIMEOUT;
    }

    public bool isNeedAlive() {
        return (_system_.currentTimeMillis() - alivetime) < RCPClient.TIMEOUT / 2;
    }

    public void bind (int lid, int sid) {
        ByteArrayOutputStream bos;

        //_system_.consoleWrite("lid:" + lid + ",sid:" + sid);
        synchronized (rcp) {
            if (lid != 0) {
                c2s_map.put (lid, sid);
                s2c_map.put (sid, lid);
                if (id_buffer.containsKey (sid) ) {
                    bos =  id_buffer.get (sid);
                }
            }
            id_buffer.remove (sid);
        }

        if (bos != nilptr) {
            if (lid != 0) {
                byte [] data = bos.toByteArray();
                if (data.length > 0) {
                    client.write (lid,  data, 0, data.length);
                }
            } else {
                rcp.getRemoteCallPipe().onSVNClose (0, sid);
            }

            bos.close();
        }
    }


    public bool create (String host, int port) {
        return rcp.create (this, host, port);
    }

    public IServer getServer() {
        return rcp.getRemoteCallPipe();
    }

    public void onrecv (int id, byte [] data, int offset,  int len) {
        synchronized (rcp) {
            if (c2s_map.containsKey (id) ) {
                getServer().onrecv (0, c2s_map.get (id), data, offset, len);
            }/*else{
                _system_.consoleWrite("onrecv has nokey\n");
            }*/
        }
    }

    public void onSVNClose (int lid) {
        synchronized (rcp) {
            int sid = c2s_map.get (lid);
            c2s_map.remove (lid);
            s2c_map.remove (sid);
            id_buffer.remove (sid);
            rcp.getRemoteCallPipe().onSVNClose (0, sid);
        }
    }


    //-----------------

    void newConnect (long context, int id) override {
        //_system_.consoleWrite("new connect\n");
        synchronized (rcp) {
            id_buffer.put (id, new ByteArrayOutputStream() );
            client.connect (id);
        }
    }

    void write (long context, int id, byte [] data, int offset, int len) override {
        synchronized (rcp) {
            if (s2c_map.containsKey (id) ) {
                int lid = s2c_map.get (id);
                client.write (lid,  data, offset, len);
            } else if (id_buffer.containsKey (id) ) {
                ByteArrayOutputStream bos =  id_buffer.get (id);
                bos.write (data, offset, len);
            }
        }
    }

    void onClose (long context, int id) override {
        synchronized (rcp) {
            if (s2c_map.containsKey (id) ) {
                int lid = s2c_map.get (id);
                s2c_map.remove (id);
                client.close (lid);
                c2s_map.remove (lid);
            }
        }
    }

    void onheartRelay (long ctx, int v) {
        alivetime = _system_.currentTimeMillis();
    }


};